﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NUnit.Framework;
using Legend.Data;
using System.Data;

namespace Legend.Core.Tests.Data
{
    [TestFixture]
    public class Define_columns
    {
        [Test]
        public void sets_columns_to_table()
        {
            var t = new DataTable();
            t.DefineColumns("a", "b");

            Assert.AreEqual("a", t.Columns[0].ColumnName);
            Assert.AreEqual("b", t.Columns[1].ColumnName);
        }

        [Test, ExpectedException(typeof(ArgumentNullException))]
        public void throws_exception_when_table_is_null()
        {
            ((DataTable)null).DefineColumns("a");
        }

        [Test, ExpectedException(typeof(InvalidOperationException))]
        public void throws_exception_if_columns_are_already_defined()
        {
            var t = new DataTable();
            t.Columns.Add("a");

            t.DefineColumns("a", "b");
        }

        [Test, ExpectedException(typeof(ArgumentNullException))]
        public void throws_exception_when_columnNames_is_null()
        {
            var t = new DataTable();
            t.DefineColumns((string[])null);
        }

        [Test]
        public void returns_table()
        {
            var t = new DataTable();

            DataTable returned = t.DefineColumns("a");
            
            Assert.AreEqual(t, returned);
        }
    }

    [TestFixture]
    public class Define_columns_with_Types
    {
        [Test, ExpectedException(typeof(ArgumentNullException))]
        public void throws_exception_when_table_is_null()
        {
            DataTable t = null;

            t.DefineColumns(new Dictionary<string, Type>{
                {"a", typeof(string)}, 
                {"b", typeof(int)}
            }); 
        }

        [Test]
        public void defines_columns_with_correct_names()
        {
            var t = new DataTable();
            t.DefineColumns(new Dictionary<string, Type> {
                {"a", typeof(string)},
                {"b", typeof(string)}
            });

            Assert.AreEqual("a", t.Columns[0].ColumnName);
            Assert.AreEqual("b", t.Columns[1].ColumnName);
        }

        [Test]
        public void defines_columns_with_correct_types()
        {
            var t = new DataTable();
            t.DefineColumns(new Dictionary<string, Type> {
                {"a", typeof(DateTime)},
                {"b", typeof(int)}
            });

            Assert.AreEqual(typeof(DateTime), t.Columns["a"].DataType);
            Assert.AreEqual(typeof(int), t.Columns["b"].DataType);
        }

        [Test]
        public void returns_table()
        {
            var t = new DataTable();
            DataTable returned;

            returned = t.DefineColumns(new Dictionary<string, Type> {
                {"a", typeof(string)},
                {"b", typeof(string)}
            });

            Assert.AreEqual(t, returned);
        }

        [Test, ExpectedException(typeof(ArgumentNullException))]
        public void throws_when_columnNamesAndTypes_is_null()
        {
            var t = new DataTable();

            t.DefineColumns((IDictionary<string, Type>)null);
        }
    }

    [TestFixture]
    public class Define_columns_with_separated_string_values
    {
        [Test, ExpectedException(typeof(ArgumentNullException))]
        public void throws_when_table_is_null()
        {
            DataTable t = null;
            t.DefineColumns(string.Empty, ',');
        }

        [Test, ExpectedException(typeof(ArgumentNullException))]
        public void throws_when_columnNames_is_null()
        {
            var t = new DataTable();
            t.DefineColumns(null, ',');
        }

        [Test, ExpectedException(typeof(ArgumentNullException))]
        public void throws_when_columnNames_is_an_empty_string()
        {
            var t = new DataTable();
            t.DefineColumns(string.Empty, ',');
        }

        [Test]
        public void sets_correct_column_names_when_column_names_are_separated_by_delimiter_and_with_no_white_space()
        {
            var t = new DataTable();
            t.DefineColumns("a,b", ',');

            Assert.AreEqual("a", t.Columns[0].ColumnName);
            Assert.AreEqual("b", t.Columns[1].ColumnName);
        }

        [Test]
        public void sets_correct_column_names_when_column_names_have_white_space()
        {
            var t = new DataTable();
            t.DefineColumns("  a, b ", ',');

            Assert.AreEqual("a", t.Columns[0].ColumnName);
            Assert.AreEqual("b", t.Columns[1].ColumnName);
        }

        [Test]
        public void returns_table()
        {
            var t = new DataTable();
            DataTable returned;

            returned = t.DefineColumns("a,b", ',');

            Assert.AreEqual(t, returned);
        }
    }

    [TestFixture]
    public class DataTableExtensions_AddRow
    {
        [Test, ExpectedException(typeof(ArgumentNullException))]
        public void throws_when_table_is_null()
        {
            DataTable t = null;
            t.AddRow();
        }

        [Test]
        public void returns_row()
        {
            var t = new DataTable();
            Assert.IsNotNull(t.AddRow());
        }
    }

    [TestFixture]
    public class DataRow_SetValue
    {
        [Test, ExpectedException(typeof(ArgumentNullException))]
        public void throws_when_row_is_null()
        {
            DataRow r = null;
            r.SetValue("a", string.Empty);
        }

        [Test, ExpectedException(typeof(ArgumentNullException))]
        public void throws_when_columnName_is_null()
        {
            var r = new DataTable().AddRow();
            r.SetValue(null, new Object());
        }

        [Test]
        public void sets_value_when_called_with_existing_column_name()
        {
            var r = new DataTable().DefineColumns("a").AddRow();
            r.SetValue("a", "a");

            Assert.AreEqual("a", r["a"]);
        }

        [Test, ExpectedException(typeof(ArgumentException))]
        public void throws_when_specified_name_of_non_existing_column()
        {
            var r = new DataTable().DefineColumns("a").AddRow();
            r.SetValue("b", new Object());
        }

        [Test]
        public void returns_row()
        {
            var r = new DataTable().DefineColumns("a").AddRow();
            DataRow returned = r.SetValue("a", string.Empty);

            Assert.AreEqual(r, returned);
        }
    }

    [TestFixture]
    public class DataRow_DoneWithRow
    {
        [Test, ExpectedException(typeof(ArgumentNullException))]
        public void throws_when_row_is_null()
        {
            DataRow r = null;
            r.DoneWithRow();
        }

        [Test]
        public void returns_table()
        {
            var t = new DataTable();

            DataTable returned = t.DefineColumns("a").AddRow().DoneWithRow();

            Assert.AreEqual(t, returned);
        }
    }
}
